#![allow(unused)]
#[cfg(feature = "enable-auto-bindings")]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

#[path = "./my_bindings.rs"]
mod my_bindings;

use crate::my_bindings::{pcre2_code_8, pcre2_compile_context_8, pcre2_compile_8,
                         pcre2_get_error_message_8, pcre2_match_data_8, pcre2_match_data_create_from_pattern_8,
                         pcre2_match_8, pcre2_match_data_free_8, pcre2_code_free_8,pcre2_get_ovector_pointer_8};

use std::ffi::{CStr, CString};
use std::os::raw;
use std::{ptr, str};
use std::mem::size_of;
use std::slice;

#[derive(Debug)]
struct MyError(String);

impl MyError {
    pub fn new(str: String) -> MyError {
        MyError(str)
    }
}

use std::fmt;
use std::fmt::{Debug, Formatter};

impl fmt::Display for MyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

use std::error::Error;
use std::io::Read;

impl Error for MyError {}

pub fn preg_match(pattern: String, subject: String) -> Result<Vec<String>, Box<dyn Error>> {
    let mut ret: Vec<String> = vec![];
    unsafe {
        let mut re: *mut pcre2_code_8 = ptr::null_mut();
        let pattern = pattern.as_ptr();
        let errornumber: raw::c_int = 0;
        let perrornumber = &errornumber as *const i32 as *mut i32;
        let mut erroroffset: usize = 0;
        let perroroffset = &erroroffset as *const usize as *mut usize;
        let pcompile_context: *mut pcre2_compile_context_8 = ptr::null_mut();
        re = pcre2_compile_8(
            pattern,
            usize::MAX,
            0u32,
            perrornumber,
            perroroffset,
            pcompile_context,
        );

        if (re.is_null())
        {
            let mut buffer: [u8; 256] = [0; 256];
            let pbuffer = &buffer[0] as *const u8 as *mut u8;
            let size = 256usize;
            pcre2_get_error_message_8(errornumber, pbuffer, size_of::<[u8; 256]>());
            let err_str = format!("compile failed at offset {}: {}\n", erroroffset, str::from_utf8(&buffer).unwrap());
            //let err = MyError::new(err_str.as_str());
            return Err(Box::new(MyError::new(err_str)));
        }

        let mut match_data: *mut pcre2_match_data_8 = ptr::null_mut();
        match_data = pcre2_match_data_create_from_pattern_8(re, ptr::null_mut());

        let rc = pcre2_match_8(
            re,
            subject.as_ptr(),
            subject.len(),
            0,
            0,
            match_data,
            ptr::null_mut());

        if rc < 1 {
            pcre2_match_data_free_8(match_data);
            pcre2_code_free_8(re);
            return Ok(ret);
        }

        let ovector = pcre2_get_ovector_pointer_8(match_data);
        let slice: &[usize] = unsafe { slice::from_raw_parts(ovector, (2 * rc) as usize) };
        for i in 0..rc
        {
            let a = [1, 2, 3];
            let b = &a[1..2];
            let sub_str: &[u8] = &subject.as_bytes()[slice[2 * i as usize]..slice[(2 * i + 1) as usize]];
            ret.push(str::from_utf8(sub_str).unwrap().to_string());
        }
        return Ok(ret);
    }
}

